package com.elvin.platform.webSocket.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@Slf4j
@ServerEndpoint("/api/pushMessage")
public class WebSocketServer {
  /**静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。*/
  private static int onlineCount = 0;
  /**concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。*/
  private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
  /**与某个客户端的连接会话，需要通过它来给客户端发送数据*/
  private Session session;
  /**接收userId*/
  private String userId = "";
  // concurrent包的线程安全Set，用来存放每个客户端对应的Session对象。
  private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();

  /**
   * 连接建立成功调用的方法
   */
  @OnOpen
  public void onOpen(Session session) {
    this.session = session;
    SessionSet.add(session);
    addOnlineCount();
    log.info("当前在线人数为:" + getOnlineCount());
    sendMessage("连接成功");
  }

  /**
   * 连接关闭调用的方法
   */
  @OnClose
  public void onClose() {
    SessionSet.remove(session);
    subOnlineCount();
    log.info("用户退出:"+session.getId()+",当前在线人数为:" + getOnlineCount());
  }

  /**
   * 收到客户端消息后调用的方法
   * @param message
   * 客户端发送过来的消息
   **/
  @OnMessage
  public void onMessage(String message, Session session) {
    log.info("用户消息:"+session.getId()+",报文:"+message);
    //可以群发消息
    //消息保存到数据库、redis
    if(StringUtils.isNotBlank(message)){
      try {
        //解析发送的报文
        /*JSONObject jsonObject = JSON.parseObject(message);
        //追加发送人(防止串改)
        jsonObject.put("fromUserId",this.userId);
        String toUserId=jsonObject.getString("toUserId");
        //传送给对应toUserId用户的websocket
        if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
          //业务
        }else{
          //userId不存在
          log.error("请求的userId:"+toUserId+"不在该服务器上");
          webSocketMap.get(this.userId).sendMessage("请求的userId:"+toUserId+"不在该服务器上");
        }*/
        BroadCastInfo(message);
      }catch (Exception e){
        e.printStackTrace();
      }
    }
  }


  public void BroadCastInfo(String message) throws IOException {
    log.info("服务端广播消息,客户端数量:"+SessionSet.size());
    for (Session session : SessionSet) {
      if (session.isOpen()) {
        SendMessage(session, message);
      }
    }
  }

  public static void SendMessage(Session session, String message) {
    try {
      synchronized(session){
        session.getBasicRemote().sendText(message);
      }
    } catch (IOException e) {
      log.error("发送消息出错：{}", e.getMessage());
      e.printStackTrace();
    }
  }

  /**
   * @param session
   * @param error
   */
  @OnError
  public void onError(Session session, Throwable error) {
    SessionSet.remove(session);
    log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
    error.printStackTrace();
  }

  /**
   * 实现服务器主动推送
   */
  public void sendMessage(String message) {
    try {
      log.info("--------------websocket主动推送数据：{}",message);
      synchronized(session){
        this.session.getBasicRemote().sendText(message);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**
   * @description: 实现服务器主动推送实体消息
   * @author Mr.Liud
   * @date 2022/6/11 9:49
   * @version 1.0
   */
  public void sendObjectMessage(Object message) {
    try {
      this.session.getBasicRemote().sendObject(message);
    } catch (IOException | EncodeException e) {
      e.printStackTrace();
    }
  }

  /**
   *发送自定义消息
   **/
  public static void sendInfo(String message, String userId) {
    log.info("发送消息到:"+userId+"，报文:"+message);
    if(StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)){
      webSocketMap.get(userId).sendMessage(message);
    }else{
      log.error("用户"+userId+",不在线！");
    }
  }

  /**
   * 获得此时的在线人数
   * @return
   */
  public static synchronized int getOnlineCount() {
    return onlineCount;
  }

  /**
   * 在线人数加1
   */
  public static synchronized void addOnlineCount() {
    WebSocketServer.onlineCount++;
  }

  /**
   * 在线人数减1
   */
  public static synchronized void subOnlineCount() {
    WebSocketServer.onlineCount--;
  }

}
